interface TimeDiff {
  day: number,
  hour: number,
  minute: number,
  second: number
}
export default class YdkDate {
  /**
    * 将一个小于两位数的值, 进行前面补0, 最终组成01, 02 等字符串
    * @param {number} num 需要补位的数字
    * @returns 返回一个字符串, 例如: 01, 02
    */
  static zeroize(num: number) {
    return (String(num).length == 1 ? "0" : "") + num;
  }
  /** 
   * 通过传入一个值, 获得解析后的时间戳
   * @param date  可以为 字符串如: 2012-03-02 | new Date() | number | undefined
   * @returns 返回一个时间戳, 当输入值为undefined的时候默认为当前时间戳
   */
  static parse(date: string | number | Date) {
    if (typeof date === 'string') {
      return Date.parse(this.canSafe(date));
    }
    return new Date(date).getTime()
  }
  /**
   * 年月日空位补0, 矫正不合格的时间日期
   * 使用场景: 将没有补0的日期都转换成标准的日期格式
   * @param timestamp number或者字符串类型(字符串: 比如2018-2-3)
   * @returns 返回一个补0的字符串日期  例如(2018-02-03)
   */
  static correct(timestamp: string | number) {
    if (!timestamp) {
      return this.format(new Date(), 'yyyy-MM-dd');
    }

    if (typeof timestamp == "string") {
      timestamp = this.parse(timestamp);
      if (timestamp === 0) {
        return "";
      }
    }

    let tmDate = new Date(timestamp); // 参数时间戳转换成的日期对象
    let Y = tmDate.getFullYear(),
      m = tmDate.getMonth() + 1,
      d = tmDate.getDate();
    return this.zeroize(Y) + "-" + this.zeroize(m) + "-" + this.zeroize(d);
  }

  /**
   * 一个发布时间格式展示规则的业务函数
   * 使用场景：发布时间展示
   * @param {(string | number)} timestamp  时间格式 字符串或者时间戳
   * @param {boolean} withTime 是否要展示时分秒
   * @returns {string} 例如: 一分钟以内：刚刚, 一小时以内："分钟前", 今天 08:00, 昨天 08:00
   */
  static publishLately(timestamp: string | number, withTime: boolean) {
    if (!timestamp) {
      return "";
    }
    if (typeof timestamp == "string") {
      timestamp = this.parse(timestamp);
      if (timestamp === 0) {
        return "";
      }
    }
    let curTimestamp = new Date().getTime(); //当前时间戳
    let timestampDiff = curTimestamp - timestamp; // 参数时间戳与当前时间戳相差秒数
    let curDate = new Date(curTimestamp); // 当前时间日期对象
    let tmDate = new Date(timestamp); // 参数时间戳转换成的日期对象
    let Y = tmDate.getFullYear(),
      m = tmDate.getMonth() + 1,
      d = tmDate.getDate();
    let H = tmDate.getHours(),
      i = tmDate.getMinutes()
    if (timestampDiff < 60 * 1000) {
      // 一分钟以内
      if (timestampDiff < 0) {
        return (
          this.zeroize(m) + "-" + this.zeroize(d) + "  " + this.zeroize(H) + ":" + this.zeroize(i)
        );
      } else {
        return "刚刚";
      }
    } else if (timestampDiff < 3600 * 1000) {
      // 一小时前之内
      return Math.floor(timestampDiff / 60 / 1000) + "分钟前";
    } else if (
      curDate.getFullYear() == Y &&
      curDate.getMonth() + 1 == m &&
      curDate.getDate() == d
    ) {
      return "今天" + this.zeroize(H) + ":" + this.zeroize(i);
    } else {
      let newDate = new Date(curTimestamp - 86400 * 1000); // 参数中的时间戳加一天转换成的日期对象
      if (
        newDate.getFullYear() == Y &&
        newDate.getMonth() + 1 == m &&
        newDate.getDate() == d
      ) {
        if (withTime) {
          return "昨天" + this.zeroize(H) + ":" + this.zeroize(i);
        } else {
          return "昨天";
        }
      } else if (curDate.getFullYear() == Y) {
        if (withTime) {
          return (
            this.zeroize(m) + "-" + this.zeroize(d) + " " + this.zeroize(H) + ":" + this.zeroize(i)
          );
        } else {
          return this.zeroize(m) + "-" + this.zeroize(d);
        }
      } else {
        if (withTime) {
          return (
            Y +
            "-" +
            this.zeroize(m) +
            "-" +
            this.zeroize(d) +
            " " +
            this.zeroize(H) +
            ":" +
            this.zeroize(i)
          );
        } else {
          return Y + "-" + this.zeroize(m) + "-" + this.zeroize(d);
        }
      }
    }
  }
  /**
   * 时间格式展示规则 假如今天未2019/7/2 18:00:00
   * 使用场景：发布时间展示
   * 展示规则：
   * 2018/1/12 12:00:00 --- 30天以上的展示为2018年1月12号 12:00
   * 2019/6/22 12:00:00 --- [3,30)天之间的展示为6月22号 12:00
   * 2019/7/1 12:00:00 --- (0,3)天之间的展示为 1天前
   * @param {string} dateStr 一个日期类型的字符串: 2019/7/2
   * @returns {string} 一天之内的展示 **小时前 一小时之内的展示 **分钟前 一分钟之内的展示 刚刚
   */
  static publish(dateStr: string) {
    let publishTime = this.parse(dateStr) / 1000,
      d_seconds,
      d_minutes,
      d_hours,
      d_days,
      timeNow = parseInt((new Date().getTime() / 1000).toString()),
      d,
      date = new Date(publishTime * 1000),
      Y = date.getFullYear(),
      M: string | number = date.getMonth() + 1,
      D: string | number = date.getDate(),
      H: string | number = date.getHours(),
      m: string | number = date.getMinutes(),
      s: string | number = date.getSeconds();
    //小于10的在前面补0

    if (M < 10) {
      M = "0" + M;
    }
    if (D < 10) {
      D = "0" + D;
    }
    if (H < 10) {
      H = "0" + H;
    }
    if (m < 10) {
      m = "0" + m;
    }
    if (s < 10) {
      s = "0" + s;
    }

    d = timeNow - publishTime;
    d_days = parseInt((d / 86400).toString());
    d_hours = parseInt((d / 3600).toString());
    d_minutes = parseInt((d / 60).toString());
    d_seconds = parseInt(d.toString());

    if (d_days > 0 && d_days < 3) {
      return d_days + "天前";
    } else if (d_days <= 0 && d_hours > 0) {
      return d_hours + "小时前";
    } else if (d_hours <= 0 && d_minutes > 0) {
      return d_minutes + "分钟前";
    } else if (d_seconds < 60) {
      return "刚刚";
    } else if (d_days >= 3 && d_days < 30) {
      return M + "月" + D + "日" + H + ":" + m;
    } else if (d_days >= 30) {
      return Y + "年" + M + "月" + D + "日" + H + ":" + m;
    }
  }

  /**
   * 使用场景:  对Date 类型的对象,转换成日期标准格式的字符串
   * 调用：formatDate('2019-07-03 13:00:00', "yyyy-M-d");
   * @param {Date} date 类型必须是时间 new Date()
   * @param {string} fmt 时间格式 yyyy-MM-dd  yyyy-M-d yyyy/MM/dd   yyyy-MM-dd hh:mm:ss
   * @returns {string} 返回一个日期标准格式的字符串 例如: 2021-03-18 2021-03-18 05:08:17
   */
  static format(date: Date | number | string, fmt: string) {
    var currentDate = new Date(date);
    var o = {
      "M+": currentDate.getMonth() + 1, //月份
      "d+": currentDate.getDate(), //日
      "h+": currentDate.getHours(), //小时
      "m+": currentDate.getMinutes(), //分
      "s+": currentDate.getSeconds(), //秒
      "q+": Math.floor((currentDate.getMonth() + 3) / 3), //季度
      S: currentDate.getMilliseconds() //毫秒
    };
    if (/(y+)/.test(fmt))
      fmt = fmt.replace(
        RegExp.$1,
        (currentDate.getFullYear() + "").substr(4 - RegExp.$1.length)
      );
    for (var k in o)
      if (new RegExp("(" + k + ")").test(fmt))
        fmt = fmt.replace(
          RegExp.$1,
          RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
        );
    return fmt;
  }

  /**
   * 根据出生日期算出年龄
   * 使用场景: 小明是1991年5月20日的生日,计算现在已经多少岁了
   * @param {string} strBirthday 以-或/连接的时间
   * @returns 返回一个number类型的年龄数值
   */
  static parseAge(strBirthday: string): number {
    let returnAge;
    let strBirthdayArr = (strBirthday || "").split("/[/,-]/");
    let birthYear = parseInt(strBirthdayArr[0]);
    let birthMonth = parseInt(strBirthdayArr[1]);
    let birthDay = parseInt(strBirthdayArr[2]);

    let d = new Date();
    let nowYear = d.getFullYear();
    let nowMonth = d.getMonth() + 1;
    let nowDay = d.getDate();

    if (nowYear == birthYear) {
      returnAge = 0; //同年 则为0岁
    } else {
      let ageDiff = nowYear - birthYear; //年之差
      if (ageDiff > 0) {
        if (nowMonth == birthMonth) {
          let dayDiff = nowDay - birthDay; //日之差
          if (dayDiff < 0) {
            returnAge = ageDiff - 1;
          } else {
            returnAge = ageDiff;
          }
        } else {
          let monthDiff = nowMonth - birthMonth; //月之差
          if (monthDiff < 0) {
            returnAge = ageDiff - 1;
          } else {
            returnAge = ageDiff;
          }
        }
      } else {
        returnAge = -1; //返回-1 表示出生日期输入错误 晚于今天
      }
    }
    return returnAge; //返回周岁年龄
  }

 /**
  * 一个计算时间差的方法, 并且会返回成 天,小时,和分钟,以及秒数
  * 使用场景: 判断两个时间对象的时间差有多少, 比如倒计时的时候
  * @param start {string} 开始的时间
  * @param end {string} 结束的时间
  * @returns 返回一个对象, 包含天数,小时数和时分秒
  */
  static parseTimeDiff(start: string | number | Date, end: string | number | Date): TimeDiff {
    let nowtime = new Date(this.parse(start)),  //获取当前时间
      endtime = new Date(this.parse(end));  //定义结束时间
    let lefttime = endtime.getTime() - nowtime.getTime(),  //距离结束时间的毫秒数
      leftd = Math.floor(lefttime / (1000 * 60 * 60 * 24)),  //计算天数
      lefth = Math.floor(lefttime / (1000 * 60 * 60) % 24),  //计算小时数
      leftm = Math.floor(lefttime / (1000 * 60) % 60),  //计算分钟数
      lefts = Math.floor(lefttime / 1000 % 60);  //计算秒数
    return {
      day: leftd,
      hour: lefth,
      minute: leftm,
      second: lefts
    }
  }

  /**
   * 一个根据日期解析当前星期几的方法
   * 场景: 获取当前星期几
   * @param {string | Date | number} date
   * @returns 返回中文星期几(例如:  星期一,星期二,星期三,星期四,星期五)
   */
  static parseWeekday(date: Date | string | number): string {
    let mydate = new Date(date);
    let myddy = mydate.getDay(); //获取存储当前日期
    let weekday = [
      "星期日",
      "星期一",
      "星期二",
      "星期三",
      "星期四",
      "星期五",
      "星期六"
    ];
    return weekday[myddy];
  }

  /**
   * 一个获取18年前的时间
   * @returns 返回距离当前时间18年前的年份
   */
  static get18Year(): string {
    const pre = new Date();
    pre.setFullYear(pre.getFullYear() - 18);
    const [y, m, d] = this.format(pre, 'yyyy-MM-dd').split('-')
    return `${y}-${m}-${d}`;
  };

  /**
   * 一个让日期格式兼容安全的方法
   * 使用场景:  比如传入日期2021-02-02 在ios可能会解析不出来,统一解析成2021/02/02
   * @param {string} date 传入的日期
   * @returns 返回一个转换之后使它安全的日期(兼容安卓ios)
   */
  static canSafe(date: string): string {
    if (typeof date === 'string') {
      return (date.replace(/-/gi, "/"));
    }
    return this.format(new Date(), 'yyyy-MM-dd').replace(/-/gi, "/")
  }


  private timer: NodeJS.Timeout | number;
  /**
   * 一个倒计时的方法
   * 使用场景: 距离xxx多少时间了, 比如距离活动开始剩余xxxx天xx小时xx分xxx秒
   * @param { number | Date | string} start  开始时间
   * @param {number | Date | string} end 结束时间
   * @param {Function} interval  每次变化时候的回调函数, 函数会带一个时分秒带参数
   */
  public countdown(start: number | Date | string, end: number | Date | string, interval: (params?: TimeDiff) => void) {
    let s = YdkDate.parse(start), e = YdkDate.parse(end);
    clearInterval(this.timer as number);
    this.timer = setInterval(() => {
      s += 1000;
      interval?.(YdkDate.parseTimeDiff(s, e) as TimeDiff)
    }, 1000)
  }

  /**
   * 停止倒计时的方法
   */
  public stopCountdown() {
    clearInterval(this.timer as number)
  }

}